/*
 * MyGWT User Extensions
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.mygwt.ux.client.widgets.impl;

import net.mygwt.ux.client.widgets.TextBox;

import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.KeyboardListenerAdapter;
import com.google.gwt.user.client.ui.Widget;

/**
 * This is the Internet Explorer specific implementation class. IE does not
 * support the input event so this class uses keyPress and paste events instead.
 * 
 * @author Damien Ferrand
 */
public class TextBoxImplIE6 extends TextBoxImpl {

	/**
	 * This method call the superclass applyStyle method and always registers a
	 * listener for the paste event.
	 * 
	 * @see net.mygwt.ux.client.widgets.impl.TextBoxImpl#applyStyle()
	 */
	public void applyStyle() {
		super.applyStyle();
		registerPasteListeners(textBox.getElement());
		registerCutListeners(textBox.getElement());
	}

	/**
	 * Registers the keyPress event listener. A listener for the keyUp event is also registered
	 * to catch the backspace and delete keys as they do not trigger a keyPress event.
	 */
	protected void registerListener() {
		textBox.addKeyboardListener(new KeyboardListenerAdapter() {
			public void onKeyPress(Widget sender, char keyCode, int modifiers) {
				final String previousValue = textBox.getText();
				char newKeyCode = keyCode;
				if ((textBox.getStyle() & TextBox.UPPERCASE) != 0) {
					newKeyCode = Character.toUpperCase(keyCode);
				}
				if ((textBox.getStyle() & TextBox.LOWERCASE) != 0) {
					newKeyCode = Character.toLowerCase(keyCode);
				}

				DOM.eventSetKeyCode(DOM.eventGetCurrentEvent(), newKeyCode);
				DeferredCommand.addCommand(new Command() {
					public void execute() {
						textBox.updatePreviousValue();
						textBox.checkValueChange(previousValue, textBox
								.getText());
					}
				});
			}

			public void onKeyUp(Widget sender, char keyCode, int modifiers) {
				final String previousValue = textBox.getPreviousValue();
				textBox.updatePreviousValue();
				DeferredCommand.addCommand(new Command() {
					public void execute() {
						textBox.checkValueChange(previousValue, textBox
								.getText());
					}
				});
			}

		});
	}

	/**
	 * Registers the paste listener.
	 * 
	 * @param element
	 *            the DOM element
	 */
	private native void registerPasteListeners(Element element) /*-{
		element.textBoxImplEI6 = this;
		element.onpaste = function(){
			$wnd.event.returnValue = false;
			element.textBoxImplEI6.@net.mygwt.ux.client.widgets.impl.TextBoxImplIE6::onPaste(Ljava/lang/String;)($wnd.clipboardData.getData("Text"));
		};
	}-*/;

	/**
	 * Registers the cut listener.
	 * 
	 * @param element
	 *            the DOM element
	 */
	private native void registerCutListeners(Element element) /*-{
		element.textBoxImplEI6 = this;
		element.oncut = function(){
			element.textBoxImplEI6.@net.mygwt.ux.client.widgets.impl.TextBoxImplIE6::onCut()();
		};
	}-*/;

	/**
	 * This method is called when the paste event fires. It cancels the normal
	 * processing and performs the paste applying the UPPERCASE or LOWERCASE
	 * style.
	 * 
	 * @param pasteValue
	 *            the text content of the clipboard
	 */
	private void onPaste(String pasteValue) {
		// Gets the previous value.
		String previousValue = textBox.getText();
		// The length of the clipboard content. Will be adjusted if necessary
		int lengthToPaste = pasteValue.length();
		// Stores the cursor position before paste
		int prevPosition = textBox.getCursorPos();

		// If the text box has a maximum length, adjust the length to paste if
		// necessary
		if (textBox.getMaxLength() > 0) {
			if (lengthToPaste + previousValue.length()
					- textBox.getSelectionLength() > textBox.getMaxLength()) {
				lengthToPaste = textBox.getMaxLength() - previousValue.length()
						+ textBox.getSelectionLength();
			}
		}

		// Change the value to paste to uppercase if necessary
		if ((textBox.getStyle() & TextBox.UPPERCASE) != 0) {
			pasteValue = pasteValue.toUpperCase();
		}

		// Change the value to lowercase if necessary
		if ((textBox.getStyle() & TextBox.LOWERCASE) != 0) {
			pasteValue = pasteValue.toLowerCase();
		}

		// Perform the paste
		textBox.setText(previousValue.substring(0, textBox.getCursorPos())
				+ pasteValue.substring(0, lengthToPaste)
				+ previousValue.substring(textBox.getCursorPos()
						+ textBox.getSelectionLength()));

		// Reposition the cursor with a deferred command
		final int newPosition = prevPosition + lengthToPaste;
		DeferredCommand.addCommand(new Command() {
			public void execute() {
				textBox.setCursorPos(newPosition);
			}
		});

		textBox.checkValueChange(previousValue, textBox.getText());
	}

	/**
	 * This method is called when a cut occurs. It will fire a ValueChangeEvent if necessary.
	 */
	private void onCut() {
		DeferredCommand.addCommand(new Command() {
			public void execute() {
				textBox.checkValueChange(textBox.getPreviousValue(), textBox
						.getText());
				textBox.updatePreviousValue();
			}
		});
	}
}